#include<sys/time.h>
#include<sys/resource.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<unistd.h>
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>

void proc_limit()
{
	/* rlim_max为RLIM_INFINITY(-1)时表无限制 */
	struct rlimit rl;
	
	/* 进程的地址空间上限，单位是字节 
	 * 超过后调用mmap 或 brk 将失败，返回 ENOMEM
	 * 进程的栈自动增长时超过，内核将给进程发送SIGSEGV信号
	 * */	
	if (getrlimit(RLIMIT_AS,&rl) < 0)
	{
		perror("getrlimit error:");
	}
	else printf("AS %ld %ld\n",rl.rlim_cur, rl.rlim_max);

	/* 栈的最大长度，超过限制将收到SIGSEGV信号
	 * */
	if (getrlimit(RLIMIT_STACK, &rl) < 0)
	{
		perror("getrlimit error:");
	}
	else printf("STACK SIZE %ld %ld\n",rl.rlim_cur, rl.rlim_max);
	
	/* 进程可以创建的最大文件，单位是字节。
	 * 如果进程扩展文件超出限制，内核将发送SIGXFSZ信号
	 * */
	if (getrlimit(RLIMIT_FSIZE, &rl) < 0)
	{
		perror("getrlimit error:");
	}
	else printf("FILE SIZE %ld %ld\n",rl.rlim_cur, rl.rlim_max);
	
	/* 一个进程可以使用的最长CPU时间，单位是秒。
	 * 如果进程运行时间超出限制，将接收内核发送出的信号：SIGXCPU
	 * LINUX允许进程继续运行，并且每秒发送给该进程一个SIGXCPU信号
	 * 一旦进程达到硬限制，将会收到SIGKILL信号并中断
	 * */
	if (getrlimit(RLIMIT_CPU, &rl) < 0)
	{
		perror("getrlimit error:");
	}
	else printf("CPU TIME %ld %ld\n",rl.rlim_cur, rl.rlim_max);
}

void sig_work(int sig)
{
	if (sig == SIGXCPU)
	{
		printf("receive a signal: SIGXCPU\n");
	}
}

int main()
{
	pid_t pid;
	printf("===========father proc============\n");
	proc_limit();
	printf("\n");

	pid = fork();
	if (pid < 0)
	{
		perror("fork error");
		exit(1);
	}
	else if (pid == 0)
	{
		printf("============child proc============\n");
		proc_limit();
		printf("\n");
	
		struct rlimit rl;
		
		/* 设置内存限制 */
		rl.rlim_cur = 1024 * 1024; 
		rl.rlim_max = rl.rlim_cur;
		if (setrlimit(RLIMIT_AS, &rl) < 0)
		{
			perror("setrlimit error:");
			exit(1);
		}

		/* 试着申请超过限制的内存*/
		char *p = (char *) malloc(1024 * 2000);
		if (p == NULL)
		{
			perror("malloc error:");
		}
		else 
		{
			printf("malloc success!\n");
		}
		p = (char *) malloc(1024 * 10);
		if (p == NULL)
		{
			perror("malloc error:");
		}
		else 
		{
			printf("malloc success!\n");
		}

		/* SIGXCPU信号的处理函数 */		
		signal(SIGXCPU, sig_work);
		rl.rlim_cur = 1; /* 软限制 */
		rl.rlim_max = 3; /* 硬限制 */
		/* 限制进程的时间 */
		if (setrlimit(RLIMIT_CPU, &rl) < 0)
		{
			perror("setrlimit error:");
			exit(1);
		}
		
		proc_limit();	
		/* 直到超过硬限制被kill */	
		while(1);
	}
	/* 父进程 */
	struct rusage ru;
	/* wait4等待pid子进程状态改变，ru为子进程使用的资源情况 */
	if ( wait4(pid, NULL, 0, &ru) < 0)
	{
		perror("wait4 error:");
	} 
	else 
	{
		printf("%ld %ld\n",ru.ru_utime.tv_sec, ru.ru_utime.tv_usec); /* 用户时间消耗 */
		printf("%ld %ld\n",ru.ru_stime.tv_sec, ru.ru_stime.tv_usec); /* 系统时间消耗 */
		printf("%ld(KB)\n",getpagesize() / 1024 * ru.ru_minflt); /* 页大小 与  page reclaims */
	}
	return 0;
}

